// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
//-
// Copyright (c) 2010 Michael Smith. All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.

/// @file       markup.h
/// @brief      format string substitution and output

// WARNING: if indices here are changed, all markup format strings
//          must be adjusted to correspond.
#define V_FLIGHTMODE    1       ///< 6 chars ASCII text
#define V_TIME          2       ///< 5 chars 0-99990
#define V_VOLTAGE       3       ///< 4 chars 0.0 - 99.9
#define V_ROLL          4       ///< 1 char glyph, 2 chars degrees 0-99 
#define V_PITCH         5       ///< 1 char glyph, 2 chars degrees 0-99 
#define V_YAW           6       ///< 1 char glyph, 2 chars degrees 0-99 
#define V_LATITUDE      7       ///< 9 chars -90.00000 - 90.00000
#define V_LONGITUDE     8       ///< 10 chars -180.00000 - 180.00000
#define V_ALTITUDE      9       ///< 4 chars 0 - 9999
#define V_GROUNDSPEED   10      ///< 3 chars -99 - 999
#define V_GROUNDCOURSE  11      ///< 3 chars 0 - 359
#define V_P_ALTITUDE    12      ///< 4 chars 0-999
#define V_AIRSPEED      13      ///< 3 chars -99 - 999

#define V_MAX           64      ///< maximum substitution code (must be multiple of 16)

// XXX might want to use uint32 and avoid the whole which-array-element question
#define AVAIL(_x)       (1 << ((_x) % 16))
#define AVAIL_HEARTBEAT (AVAIL(V_FLIGHTMODE) | AVAIL(V_TIME)      | AVAIL(V_VOLTAGE))
#define AVAIL_ATTITUDE  (AVAIL(V_ROLL)       | AVAIL(V_YAW)       | AVAIL(V_PITCH))
#define AVAIL_LOCATION  (AVAIL(V_LATITUDE)   | AVAIL(V_LONGITUDE) | AVAIL(V_ALTITUDE) | AVAIL(V_GROUNDSPEED) | AVAIL(V_GROUNDCOURSE))
#define AVAIL_PRESSURE  (AVAIL(V_P_ALTITUDE) | AVAIL(V_AIRSPEED))

class Markup {
public:
        Markup() {};

        void            emit(const prog_char *str);
        static void     message(void *arg, uint8_t messageID, uint8_t messageVersion, void *buf);
private:
        void            _substitute(uint8_t key);
        uint16_t        _subAttitude(int16_t value, uint8_t glyphNegative, uint8_t glyphPositive);
        bool            _available(uint8_t key);
        void            _message(uint8_t messageID, uint8_t messageVersion, void *buf);
        uint16_t        _availability[V_MAX / 16];

        // cached packets
        struct msg_heartbeat    _heartbeat;
        struct msg_attitude     _attitude;
        struct msg_location     _location;
        struct msg_pressure     _pressure;
        // ... more?
};

